﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Common;

namespace ImageProcessPlugins
{
    public partial class HY_ScissorForm : Form
    {
        public HY_ScissorForm()
        {
            InitializeComponent();
        }

        Bitmap bitmap;

        public void SetBitmap(Bitmap bmp)
        {
            bitmap = bmp;
            Document doc = new Document();
            doc.SetBitmap(bmp);
            view.SetDocument(doc);
            view.ViewMode = ViewMode.BestFit;
        }

        int ox, oy;
        int nx, ny;
        Rectangle imgRect = new Rectangle(0,0,0,0);
        OperationState state = OperationState.Start;
        const int ControlPointSize = 4;
        OperationState GetNextState(int x, int y)
        {
            Rectangle rect = GetScreenSpaceRectangle();
            Point p = view.ImageSpacePointToScreenSpacePoint(new Point(x, y));
            Rectangle r0 = new Rectangle(rect.Left - ControlPointSize, rect.Top - ControlPointSize,
                ControlPointSize * 2, ControlPointSize * 2);
            if (r0.Contains(p))
                return OperationState.ResizeTopLeft;
            r0 = new Rectangle(rect.Left - ControlPointSize, rect.Top + rect.Size.Height / 2 - ControlPointSize, ControlPointSize * 2,
                ControlPointSize * 2);
            if (r0.Contains(p))
                return OperationState.ResizeLeft;

            r0 = new Rectangle(rect.Left - ControlPointSize, rect.Top + rect.Size.Height-ControlPointSize, ControlPointSize * 2,
                ControlPointSize * 2);
            if (r0.Contains(p))
                return OperationState.ResizeLeftBottom;

            r0 = new Rectangle(rect.Left + rect.Size.Width/2 - ControlPointSize, rect.Top + rect.Size.Height - ControlPointSize, ControlPointSize * 2,
               ControlPointSize * 2);
            if (r0.Contains(p))
                return OperationState.ResizeBottom;

            r0 = new Rectangle(rect.Left + rect.Size.Width - ControlPointSize, rect.Top + rect.Size.Height - ControlPointSize, ControlPointSize * 2,
               ControlPointSize * 2);
            if (r0.Contains(p))
                return OperationState.ResizeRightBottom;

            r0 = new Rectangle(rect.Left + rect.Size.Width - ControlPointSize, rect.Top + rect.Size.Height/2 - ControlPointSize, ControlPointSize * 2,
               ControlPointSize * 2);
            if (r0.Contains(p))
                return OperationState.ResizeRight;

            r0 = new Rectangle(rect.Left + rect.Size.Width - ControlPointSize, rect.Top - ControlPointSize, ControlPointSize * 2,
              ControlPointSize * 2);
            if (r0.Contains(p))
                return OperationState.ResizeTopRight;

            r0 = new Rectangle(rect.Left + rect.Size.Width/2 - ControlPointSize, rect.Top  - ControlPointSize, ControlPointSize * 2,
              ControlPointSize * 2);
            if (r0.Contains(p))
                return OperationState.ResizeTop;

            return OperationState.CreatedRectangle;

        }
        private void view_ImageMouseDown(int x, int y)
        {
            switch (state)
            {
                case OperationState.Start:
                    {
                        ox = x;
                        oy = y;
                        imgRect.X = ox;
                        imgRect.Y = oy;
                        state = OperationState.CreatingRectangle;
                    }
                    break;
                case OperationState.CreatedRectangle:
                    {
                        ox = x;
                        oy = y;
                        if (imgRect.Contains(new Point(x, y)))
                        {
                            state = OperationState.MoveRectangle;
                        }
                        else
                        {
                            state = GetNextState(x, y);
                        }
                    }
                    break;
            }
        }

        private void view_ImageMouseMove(int x, int y)
        {
           
            switch (state)
            {
                case OperationState.Start:
                    {
                        view.Cursor = Cursors.Cross;
                        yTextBox.Text = y.ToString();
                        xTextBox.Text = x.ToString();
                    }
                    break;
                case OperationState.CreatingRectangle:
                    { 
                        view.Cursor = Cursors.Cross;
                        UpdateRect_CreateRect(x, y);
                        UpdateTextBox();
                    }
                    break;
                case OperationState.CreatedRectangle:
                    {
                        if (imgRect.Contains(new Point(x, y)))
                        {
                            view.Cursor = Cursors.SizeAll;
                        }
                        else
                        {
                            switch(GetNextState(x,y))
                            {
                                case OperationState.ResizeBottom:
                                case OperationState.ResizeTop:
                                    view.Cursor = Cursors.SizeNS;
                                    break;
                                case OperationState.ResizeLeft:
                                case OperationState.ResizeRight:
                                    view.Cursor = Cursors.SizeWE;
                                    break;
                                case OperationState.ResizeTopLeft:
                                case OperationState.ResizeRightBottom:
                                    view.Cursor = Cursors.SizeNWSE;
                                    break;
                                case OperationState.ResizeTopRight:
                                case OperationState.ResizeLeftBottom:
                                    view.Cursor = Cursors.SizeNESW;
                                    break;
                                default:
                                    view.Cursor = Cursors.Default;
                                    break;

                            }
                        }
                    }
                    break;
                case OperationState.MoveRectangle:
                    {
                        nx = x;
                        ny = y;
                        int dx = nx - ox;
                        int dy = ny - oy;
                        imgRect.X += dx;
                        imgRect.Y += dy;
                        ox = nx;
                        oy = ny;
                        UpdateTextBox();
                        view.Cursor = Cursors.SizeAll;
                    }
                    break;
                case OperationState.ResizeBottom:
                    {
                        int dy = y - oy;
                        oy = y;
                        if (imgRect.Height + dy > 0)
                            imgRect.Height += dy;
                        UpdateTextBox();
                    }
                    break;
                case OperationState.ResizeTop:
                    {
                        int dy = y - oy;
                        oy = y;
                        if (imgRect.Height - dy > 0)
                        {
                            imgRect.Y += dy;
                            imgRect.Height -= dy;
                        }
                        UpdateTextBox();
                    }
                    break;
                case OperationState.ResizeLeft:
                    {
                        int dx = x - ox;
                        ox = x;
                        if (imgRect.Width - dx > 0)
                        {
                            imgRect.X += dx;
                            imgRect.Width -= dx;
                        }
                        UpdateTextBox();
                    }
                    break;
                case OperationState.ResizeRight:
                    {
                        int dx = x - ox;
                        ox = x;
                        if (imgRect.Width + dx > 0)
                            imgRect.Width += dx;
                        UpdateTextBox();
                    }
                    break;
                case OperationState.ResizeRightBottom:
                    {
                        int dx = x - ox;
                        ox = x;
                        if (imgRect.Width + dx > 0)
                            imgRect.Width += dx;
                        int dy = y - oy;
                        oy = y;
                        if (imgRect.Height + dy > 0)
                            imgRect.Height += dy;
                        UpdateTextBox();
                    }
                    break;
                case OperationState.ResizeTopLeft:
                    {
                        int dy = y - oy;
                        oy = y;
                        if (imgRect.Height - dy > 0)
                        {
                            imgRect.Y += dy;
                            imgRect.Height -= dy;
                        }
                        int dx = x - ox;
                        ox = x;
                        if (imgRect.Width - dx > 0)
                        {
                            imgRect.X += dx;
                            imgRect.Width -= dx;
                        }
                        UpdateTextBox();
                    }
                    break;
                case OperationState.ResizeTopRight:
                    {
                        int dy = y - oy;
                        oy = y;
                        if (imgRect.Height - dy > 0)
                        {
                            imgRect.Y += dy;
                            imgRect.Height -= dy;
                        }
                        int dx = x - ox;
                        ox = x;
                        if (imgRect.Width + dx > 0)
                            imgRect.Width += dx;
                        UpdateTextBox();
                    }
                    break;
                case OperationState.ResizeLeftBottom:
                    {
                        int dy = y - oy;
                        oy = y;
                        if (imgRect.Height + dy > 0)
                            imgRect.Height += dy;
                        int dx = x - ox;
                        ox = x;
                        if (imgRect.Width - dx > 0)
                        {
                            imgRect.X += dx;
                            imgRect.Width -= dx;
                        }
                        UpdateTextBox();
                    }
                    break;
            }
            ClampImageRectangle();
            view.RefreshOverlay();
        }

        private void UpdateTextBox()
        {
            xTextBox.TextChanged -= new EventHandler(xTextBox_TextChanged);
            yTextBox.TextChanged -= new EventHandler(yTextBox_TextChanged);
            widthTextBox.TextChanged -= new EventHandler(widthTextBox_TextChanged);
            heightTextBox.TextChanged -= new EventHandler(heightTextBox_TextChanged);
            yTextBox.Text = imgRect.X.ToString();
            xTextBox.Text = imgRect.Y.ToString();
            widthTextBox.Text = imgRect.Width.ToString();
            heightTextBox.Text = imgRect.Height.ToString();
            xTextBox.TextChanged += new EventHandler(xTextBox_TextChanged);
            yTextBox.TextChanged += new EventHandler(yTextBox_TextChanged);
            widthTextBox.TextChanged += new EventHandler(widthTextBox_TextChanged);
            heightTextBox.TextChanged += new EventHandler(heightTextBox_TextChanged);
            xTextBox.Refresh();
            yTextBox.Refresh();
            widthTextBox.Refresh();
            heightTextBox.Refresh();
        }

        private void ClampImageRectangle()
        {
            if (imgRect.X < 0)
                imgRect.X = 0;
            if (imgRect.Y < 0)
                imgRect.Y = 0;
            if (imgRect.Bottom > bitmap.Height)
            {
                imgRect.Y = bitmap.Height - imgRect.Height;
                if (imgRect.Y < 0)
                {
                    imgRect.Y = 0;
                    imgRect.Height = bitmap.Height - imgRect.Y;
                }
            }
            if (imgRect.Right > bitmap.Width)
            {
                imgRect.X = bitmap.Width - imgRect.Width;
                if (imgRect.X < 0)
                {
                    imgRect.X = 0;
                    imgRect.Width = bitmap.Width - imgRect.X;
                }
            }
        }
        private void UpdateRect_CreateRect(int x, int y)
        {
            nx = x;
            ny = y;
            imgRect.Height = Math.Abs(ny - oy);
            imgRect.Width = Math.Abs(nx - ox);
            if (nx < ox)
                Swap(ref ox, ref nx);
            if (ny < oy)
                Swap(ref oy, ref ny);
        }
        private void Swap(ref int ox, ref int nx)
        {
            int tmp = ox;
            ox = nx;
            nx = tmp;
        }

        private void view_ImageMouseUp(int x, int y)
        {
            switch (state)
            {
                case OperationState.CreatingRectangle:
                    {
                        UpdateRect_CreateRect(x, y);
                        UpdateTextBox();
                        state = OperationState.CreatedRectangle;
                    }
                    break;
                default:
                    {
                        state = OperationState.CreatedRectangle;
                    }
                    break;
            }
            view.RefreshOverlay();
        }

        Rectangle GetScreenSpaceRectangle()
        {
            Point p0 = new Point(imgRect.Left, imgRect.Top);
            Point p1 = new Point(imgRect.Right, imgRect.Bottom);
            Point scrP0 = view.ImageSpacePointToScreenSpacePoint(p0);
            Point scrP1 = view.ImageSpacePointToScreenSpacePoint(p1);
            return new Rectangle(scrP0.X, scrP0.Y, scrP1.X - scrP0.X, scrP1.Y - scrP0.Y);
        }

        private void view_DrawOverlay(Graphics g, Rectangle imageRect)
        {
            if (state == OperationState.Start)
                return;
            Rectangle screenRect = GetScreenSpaceRectangle();
            Region r = new Region(ClientRectangle);
            r.Xor(screenRect);
            g.FillRegion(new SolidBrush(Color.FromArgb(128,0,0,0)), r);

            g.DrawRectangle(Pens.Red, screenRect);
            // Draw Control Points
            Rectangle rect = GetScreenSpaceRectangle();

            Rectangle r0 = new Rectangle(rect.Left - ControlPointSize, rect.Top - ControlPointSize,
                ControlPointSize * 2, ControlPointSize * 2);
            g.FillRectangle(Brushes.Red, r0);

            r0 = new Rectangle(rect.Left - ControlPointSize, rect.Top + rect.Size.Height / 2 - ControlPointSize, ControlPointSize * 2,
                ControlPointSize * 2);
            g.FillRectangle(Brushes.Red, r0);

            r0 = new Rectangle(rect.Left - ControlPointSize, rect.Top + rect.Size.Height - ControlPointSize, ControlPointSize * 2,
                ControlPointSize * 2);
            g.FillRectangle(Brushes.Red, r0);

            r0 = new Rectangle(rect.Left + rect.Size.Width / 2 - ControlPointSize, rect.Top + rect.Size.Height - ControlPointSize, ControlPointSize * 2,
               ControlPointSize * 2);
            g.FillRectangle(Brushes.Red, r0);

            r0 = new Rectangle(rect.Left + rect.Size.Width - ControlPointSize, rect.Top + rect.Size.Height - ControlPointSize, ControlPointSize * 2,
               ControlPointSize * 2);
            g.FillRectangle(Brushes.Red, r0);

            r0 = new Rectangle(rect.Left + rect.Size.Width - ControlPointSize, rect.Top + rect.Size.Height / 2 - ControlPointSize, ControlPointSize * 2,
               ControlPointSize * 2);
            g.FillRectangle(Brushes.Red, r0);

            r0 = new Rectangle(rect.Left + rect.Size.Width - ControlPointSize, rect.Top - ControlPointSize, ControlPointSize * 2,
              ControlPointSize * 2);
            g.FillRectangle(Brushes.Red, r0);

            r0 = new Rectangle(rect.Left + rect.Size.Width / 2 - ControlPointSize, rect.Top - ControlPointSize, ControlPointSize * 2,
              ControlPointSize * 2);
            g.FillRectangle(Brushes.Red, r0);
        }

        private void xTextBox_TextChanged(object sender, EventArgs e)
        {
            int val;
            Int32.TryParse(xTextBox.Text, out val);
            imgRect.X = val;
            ClampImageRectangle();
            view.RefreshOverlay();
        }

        private void yTextBox_TextChanged(object sender, EventArgs e)
        {
            int val;
            Int32.TryParse(yTextBox.Text, out val);
            imgRect.Y = val;
            ClampImageRectangle();
            view.RefreshOverlay();
        }

        private void widthTextBox_TextChanged(object sender, EventArgs e)
        {
            int val;
            Int32.TryParse(widthTextBox.Text, out val);
            imgRect.Width = val;
            ClampImageRectangle();
            view.RefreshOverlay();
        }

        private void heightTextBox_TextChanged(object sender, EventArgs e)
        {
            int val;
            Int32.TryParse(heightTextBox.Text, out val);
            imgRect.Height = val;
            ClampImageRectangle();
            view.RefreshOverlay();
        }

        public Rectangle GetImageRectangle()
        {
            return imgRect;
        }

        private void cancelButton_Click(object sender, EventArgs e)
        {
            DialogResult = DialogResult.Cancel;
        }

        private void okButton_Click(object sender, EventArgs e)
        {
            if (imgRect.Height > 0 && imgRect.Width > 0 && imgRect.X >= 0 && imgRect.Y >= 0)
                DialogResult = DialogResult.OK;
            else
                MessageBox.Show("Illegal clipping rectangle.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
        }

    }


    enum OperationState
    {
        Start, CreatingRectangle, CreatedRectangle, MoveRectangle, ResizeTop, ResizeLeft, ResizeBottom, ResizeRight,
        ResizeRightBottom, ResizeTopLeft, ResizeLeftBottom, ResizeTopRight
    }
}
